package com.example.dailyrecord.service.impl;

import com.example.dailyrecord.base.entity.ResultMsg;
import com.example.dailyrecord.base.entity.SQLBuilder;
import com.example.dailyrecord.base.service.impl.BaseServiceImpl;
import com.example.dailyrecord.entity.EmailContent;
import com.example.dailyrecord.entity.StatusCode;
import com.example.dailyrecord.entity.User;
import com.example.dailyrecord.service.UserService;
import com.example.dailyrecord.util.FunctionUtils;
import com.example.dailyrecord.util.PasswordEncoder;
import com.example.dailyrecord.util.RequestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl extends BaseServiceImpl<User> implements UserService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public StatusCode register(HttpServletRequest request, HttpServletResponse response) {
        String email = request.getParameter(User.EMAIL_NAME);
        String password = request.getParameter(User.PASSWORD_NAME);
        String code = request.getParameter("code");
        String name = request.getParameter("name");
        //先检查此邮箱是否已注册过
        if (checkAccountExist(email)) {
            return StatusCode.USER_ALREADY_EXIST;
        }
        //校验验证码
        StatusCode checkCode = checkCode(email, code, 0);
        if (checkCode != StatusCode.SUCCESS) {
            return checkCode;
        }

        insert(User.init(email, password, name));
        return StatusCode.REGISTER_SUCCESS;
    }

    @Override
    public StatusCode updatePass(HttpServletRequest request, HttpServletResponse response) {
        String email = request.getParameter(User.EMAIL_NAME);
        String password = request.getParameter(User.PASSWORD_NAME);
        String code = request.getParameter("code");
        if (!checkAccountExist(email)) {
            return StatusCode.USER_NOT_EXIST;
        }
        StatusCode checkCode = checkCode(email, code, 1);
        if (checkCode != StatusCode.SUCCESS) {
            return checkCode;
        }
        updatePass(email, PasswordEncoder.encoder(password));
        return StatusCode.UPDATE_PASS_SUCCESS;
    }

    @Override
    public ResultMsg login(HttpServletRequest request, HttpServletResponse response) {
        String email = request.getParameter(User.EMAIL_NAME);
        String password = request.getParameter(User.PASSWORD_NAME);
        if (!checkAccountExist(email)) {
            return ResultMsg.getInstance(null, StatusCode.USER_NOT_EXIST);
        }
        User userInDB = selectByEmail(email);
        if (!userInDB.isAccountNonLocked()) {
            return ResultMsg.getInstance(null, StatusCode.ACCOUNT_LOCK);
        }
        if (!PasswordEncoder.matches(password, userInDB.getPassword())) {
            //密码错误次数+1
            int wrongNum = userInDB.getWrongTimes() + 1;
            userInDB.setWrongTimes(wrongNum);
            update(userInDB);
            if (wrongNum > User.MAX_WRONG) {
                return ResultMsg.getInstance(null, StatusCode.ACCOUNT_LOCK);
            }
            return ResultMsg.getInstance(null, StatusCode.PASS_WRONG);
        }
        userInDB.setLastLoginTime(FunctionUtils.getNowTime());
        userInDB.setWrongTimes(0);
        update(userInDB);
        String token = tokenUtils.create(email);
        RequestUtils.setToken(response, token);
        stringRedisTemplate.opsForValue().set(email, token, 7, TimeUnit.DAYS);
        return ResultMsg.getInstance(userInDB, StatusCode.LOGIN_SUCCESS);
    }

    @Override
    public void clearCwcs() {
        String oneHourAgo = LocalDateTime.now().minusHours(1).format(FunctionUtils.YYYYMMDDHHMMSS);
        SQLBuilder sqlBuilder = SQLBuilder.getInstance().update(User.TABLE_NAME)
                .set()
                .eq(User.WRONGTIMES_COLUMN, 0)
                .where()
                .eq(User.WRONGTIMES_COLUMN, User.MAX_WRONG + 1)
                .and().lte(User.LASTLOGINTIME_COLUMN, oneHourAgo);
        updateFree(sqlBuilder);
    }

    private User selectByEmail(String email) {
        SQLBuilder sqlBuilder = SQLBuilder.getInstance()
                .eq(User.EMAIL_COLUMN, email);
        return selectFree(sqlBuilder);
    }

    private boolean checkAccountExist(String email) {
        long count = countByBuilder(SQLBuilder.getInstance().eq(User.EMAIL_COLUMN, email));
        return count == 1;
    }

    private StatusCode checkCode(String email, String code, int type) {
        //校验验证码
        EmailContent emailContent = EmailContent.getContent(type);
        String redisCode = stringRedisTemplate.opsForValue().get(email + emailContent.getAction());
        if (StringUtils.isEmpty(redisCode)) {
            return StatusCode.CODE_INVALID;
        }
        if (!StringUtils.equals(code, redisCode)) {
            return StatusCode.CODE_WRONG;
        }
        return StatusCode.SUCCESS;
    }

    private void updatePass(String email, String pass) {
        SQLBuilder sqlBuilder = SQLBuilder.getInstance()
                .update(User.TABLE_NAME)
                .set()
                .eq(User.PASSWORD_COLUMN, pass)
                .where()
                .eq(User.EMAIL_COLUMN, email);
        updateFree(sqlBuilder);
    }
}
